// my extensions
Array.extend({
	find: function(fn, from, bind){
		var len = this.length;
		for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
			if (fn.call(bind, this[i], i, this)) return i;
		}
		return -1;
	},
	
	binarySearch: function (compareFn, value, from, length, bind) {
		var len = this.length;		
		var lo = (from < 0) ? Math.max(0, len + from) : from || 0;
		var hi = ($defined(length) ? (lo + length) : len) - 1;
		
		while (lo <= hi) {
			current = (lo + ((hi - lo) >> 1)).toInt();
			result = compareFn(this[current], value);
			if (result == 0)
				return current;
				
			if (result < 0)
				lo = current + 1;
			else 
				hi = current - 1; 
		}
		return ~lo;
	},
	
	unique: function(equalsFn) {
		equalsFn = $pick(equalsFn, function (a, b) {
			return a == b;
		});
	
		var result = [];
		this.each(function (outterItem) {
			if (result.find(function (item) {
				return equalsFn(item, outterItem);
			}) == -1) {
				result.push(outterItem);
			}
		});
		return result;
	},
	
	same: function (other) {
		if (this.length != other.length) {
			return false;
		} else {
			for (var i = 0; i < this.length; i++) {
				if (this[i] != other[i]) {
					return false;
				}
			}
			return true;
		}
	}
});

Number.extend({
	fixedString: function(digit) {
		var str = this + "";
		var zeroes = digit - str.length;
		if (zeroes <= 0) {
			return str;
		} else {
			var prefix = "";
			zeroes.times(function(){
				prefix = "0" + prefix;
			});
			return prefix + str;
		}
	},
	
	inRange: function(lo, hi) {
		return this >= lo && this < hi;
	}
});

String.extend({
	startsWith: function (str, ignoreCase) {
		ignoreCase = $pick(ignoreCase, false);
		var currentStr = ignoreCase ? this.toLowerCase() : this;
		var str = ignoreCase ? str.toLowerCase() : str;
		return currentStr.indexOf(str) === 0;
	},

	endsWith: function (str, ignoreCase) {
		ignoreCase = $pick(ignoreCase, false);
		var currentStr = ignoreCase ? this.toLowerCase() : this;
		var str = ignoreCase ? str.toLowerCase() : str;
		return currentStr.indexOf(str) === (currentStr.length - str.length);
	},
	
	format: function () {
		var fragments = this.split('?');
		var args = arguments;
		var rslt = fragments[0];
		for (var i = 1; i < fragments.length; i++) {
			rslt += $pick(args[i - 1], '') + fragments[i];
		}
		return rslt;
	},
	
	substitute: function(object, regexp){
		return this.replace(regexp || (/\\?\{([^}]+)\}/g), function(match, name){
			if (match.charAt(0) == '\\') return match.slice(1);
			return (object[name] != undefined) ? object[name] : '';
		});
	}
});

Element.Layout = {Left : 0, Right : 1, Center : 2};
Element.extend({
	flowLayout: function (layout) {
		suppressUpdates();
		layout = $pick(layout, Element.Layout.Left);

		var nextTop = 0, nextLeft = 0;
		var maxHeight = 0;
		var parentWidth = this.getParent() ? this.getParent().width : this.width;
		var row = 0;
		
		switch (layout) {
			case Element.Layout.Left:
				var initialLeft = function () {
					return 0;
				};
				var checkIfNextLine = function (control, left) {
					return (left + control.width) > parentWidth;
				};
				var getLeft = function(control, left) {
					return left;
				}
				var getNextLeft = function(control, left) {
					return left + control.width;
				}
				break;
			case Element.Layout.Right:
				var initialLeft  = function () {
					return parentWidth;
				};
				var checkIfNextLine = function (control, left) {
					return (left - control.width) < 0;
				};
				var getLeft = function(control, left) {
					return left - control.width;
				}
				var getNextLeft = function(control, left) {
					return left - control.width;
				}
				break;
			case Element.Layout.Center:
				var lineWidth = []; 
				var current = 0;
				$each(this.getChildren(), function (control){
					if (current + control.width > parentWidth) {
						lineWidth.push(current);
						current = 0;
					}
					current += control.width;
				});
				lineWidth.push(current);
				
				var initialLeft  = function (row) {
					return (parentWidth - lineWidth[row]) / 2;
				};
				var checkIfNextLine = function (control, left, row) {
					return (left + control.width) > lineWidth[row];
				};
				var getLeft = function(control, left) {
					return left;
				}
				var getNextLeft = function(control, left) {
					return left + control.width;
				}
				break;
		}
		
		nextLeft = initialLeft(row);
		$each(this.getChildren(), function (control) {
			if (!control.visible) {
				return;
			}
			
			if (checkIfNextLine(control, nextLeft)) {
				row++;
				
				nextLeft = initialLeft(row);
				nextTop += maxHeight;
				maxHeight = 0;
			}
			control.hOffset = getLeft(control, nextLeft);
			control.vOffset = nextTop;
			maxHeight = Math.max(maxHeight, control.height);
			
			nextLeft = getNextLeft(control, nextLeft);
		});
		resumeUpdates();
	},
	
	toggleStyle: function (prop, defaultStyle, newStyle) {
		var notPropStyle = '$not' + prop + 'Style'; 
		if (!this[notPropStyle]) {
			this[notPropStyle] = {};
			for (var p in newStyle) {
				this[notPropStyle][p] = this.style[p] ? this.style[p] : defaultStyle[p];
			}
			this.setStyles(newStyle);
		} else {
			this.setStyles(this[notPropStyle]);
			delete this[notPropStyle];
		}
	},
	
	getBounds: function () {
		return Rectangle.create(this.hOffset, this.vOffset, this.width, this.height);
	}
});

Event.keys.shift = 16;
Event.keys.control = 17;

$extend(Class.prototype, {
	isInstance: function (instance) {
		return this.prototype.isPrototypeOf(instance);
	}, 
	
	isAssignableFrom: function (klazz) {
		if (klazz == undefined 
			|| klazz.prototype == undefined) {
			return false;
		}
		
		for (var prop in this.prototype) {
			if (klazz.prototype.__lookupGetter__(prop) == undefined 
				&& klazz.prototype.__lookupSetter__(prop) == undefined 
				&& klazz.prototype[prop] == undefined) {
				return false;
			}
		}
		return true;
	},
	
	getterDefined: function (field) {
		return $defined(this.prototype.__lookupGetter__(field));
	},
	
	defineGetter: function (field, fn, overwrite) {
		overwrite = $pick(overwrite, false);
		if (overwrite || !this.getterDefined(field)){
			this.prototype.__defineGetter__(field, fn);
		}
	},
	
	setterDefined: function (field) {
		return $defined(this.prototype.__lookupSetter__(field));
	},
	
	defineSetter: function (field, fn, overwrite) {
		overwrite = $pick(overwrite, false);
		if (overwrite || !this.setterDefined(field)){
			this.prototype.__defineSetter__(field, fn);
		}
	}
});

function fetchResult(result, row, field) {
	var allResult = result.getAll();
	row = $pick(row, 0);
	result.dispose();
	if (allResult.length <= row) {
		return false;
	} else {
		field = $pick(field, 0);
		var i = 0;
		for (var f in allResult[row]) {
			if (field == f || field == i) {
				return allResult[row][f];
			}
			i++;
		}
	}
}

var Time = new Class({
	options: {
		second: 0,
		minute: 0,
		hour: 0,
		day: 0
	},
	
	initialize: function (options) {
		this.setOptions(options);
		this.$seconds = 0;
		
		var timeMap = 
		{
			second : 1, 
			minute : 60, 
			hour : 60 * 60, 
			day: 60 * 60 * 24
		};
		for (var p in timeMap) {
			this.$seconds += this.options[p] * timeMap[p];
		}
		
		var t = new Date(this.$seconds * 1000);
		this.second = t.getUTCSeconds();
		this.minute = t.getUTCMinutes();
		this.hour = t.getUTCHours();
		this.day = t.getUTCDate() - 1;
	},
	
	toString : function () {
		return  (this.day ? this.day + ":": "") +
				(this.hour ? this.hour.fixedString(2) + ":" : "") +
				(this.minute.fixedString(2) + ":") +
				(this.second.fixedString(2));
	}, 
	
	valueOf: function () {
		return this.$seconds;
	},
	
	equals: function (other) {
		if (!Time.isInstance(other)) {
			return false;
		}
		
		return this.valueOf() == other.valueOf();
	}
});
Time.implement(new Options);

function print_r( array ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Michael White (http://crestidg.com)
    // +   improved by: Ben Bryan
    // *     example 1: print_r(1);
    // *     returns 1: 1
 
    var output = "", pad_char = " ", pad_val = 4;
 
    var formatArray = function (obj, cur_depth, pad_val, pad_char) {
        if (cur_depth > 0) {
            cur_depth++;
        }
 
        var base_pad = repeat_char(pad_val*cur_depth, pad_char);
        var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char);
        var str = "";
 
        if (obj instanceof Array || obj instanceof Object) {
            str += "Array\n" + base_pad + "(\n";
            for (var key in obj) {
                if (obj[key] instanceof Array) {
                    str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char);
                } else {
                    str += thick_pad + "["+key+"] => " + obj[key] + "\n";
                }
            }
            str += base_pad + ")\n";
        } else {
            str = obj.toString();
        }
 
        return str;
    };
 
    var repeat_char = function (len, pad_char) {
        var str = "";
        for(var i=0; i < len; i++) { 
            str += pad_char; 
        };
        return str;
    };
    output = formatArray(array, 0, pad_val, pad_char);
 
    return output;
}

var KonStyle = new Class({
	options: {
		background: "",
		backgroundAttachment: "",
		backgroundColor: "",
		backgroundImage: "",
		backgroundPosition: "",
		backgroundRepeat: "",
		color: "",
		fontFamily: "",
		fontSize: "",
		fontStretch: "",
		fontStyle: "",
		fontWeight: "",
		KonBackgroundFill: "",
		KonShadow: "",
		KonShadowColor: "",
		KonShadowOffset: "",
		KonTextTruncation: "",
		opacity: "",
		textAlign: "",
		textDecoration: ""
	},
	
	initialize: function (options) {
		this.setOptions(options);
		for (var prop in this.options) {
			this[prop] = this.options[prop];
		}
		this.options = null;
	}, 
	
	getProperties: function () {
		var properties = {};
		for (var prop in this) {
			if (this[prop] && $type(this[prop]) != 'function') {
				properties[prop] = this[prop];
			}
		}
		return properties;
	},
	
	applyTo: function (element) {
		for (var prop in this) {
			if (this[prop] && $type(this[prop]) != 'function') {
				element.style[prop] = this[prop];
			}
		}
	},
	
	inheritAll: function (element) {
		if (element.parentNode) {
			var parentStyle = KonStyle.cloneStyle(element.parentNode);
			for (var prop in this) {
				if (this[prop] && $type(this[prop]) != 'function') {
					element.style[prop] = parentStyle[prop];
				}
			}
		}
	},
	
	toString: function () {
		var str = "{";
		for (var prop in this) {
			if ($type(this[prop]) != 'function') {
				str += prop + ":" + this[prop] + "\n";
			}
		}
		str += "}";
		return str;
	}
});
KonStyle.implement(new Options);
KonStyle.cloneStyle = function (element) {
	var style = new KonStyle(element.style);
	for (var prop in style) {
		if (prop == 'options') 
			continue;
	
		if ($type(style[prop]) != 'function' && !style[prop]) {
			var parentNode = element.parentNode;
			while (parentNode && (!parentNode['style'] || !parentNode.style[prop])) {
				parentNode = parentNode.parentNode;
			}
			
			if (parentNode && parentNode.style) {
				style[prop] = parentNode.style[prop];
			}
		}
	}
	return style;
}

var KonPanel = new Class({
	options: {
		defaultScrollBarWidth: 20,
		scrollAutoHide: false
	},
	
	initialize: function (el, options) {
		if (el.getTag() != 'frame') 
			throw 'element must be a frame';
			
		this.$pane = el;
		this.setOptions(options);
		
		this.$vScroll = this.$pane.getNext();
		this.$hScroll = this.$vScroll ? this.$vScroll.getNext() : null;
		
		if ((this.$pane.vScrollBar) || (this.$vScroll && this.$vScroll.getTag() == 'scrollbar')) {
			if (this.$pane.vScrollBar)
				this.$vScroll = $(this.$pane.vScrollBar);
				
			this.$vScroll.set({
				autoHide: this.options.scrollAutoHide,
				orientation: 'vertical',
				hAlign: this.$pane.vScrollBar ? 'right' : null,
				visible: true,
				vOffset: this.$pane.vOffset,
				width: this.options.defaultScrollBarWidth,
				min: 0
			});
			
			this.$pane.addEvent('MouseWheel', function (event) {
				this.$vScroll.value -= event.scrollDelta * 10;
			}.bind(this));
			this.$pane.__defineGetter__('vScroll', function () {
				return this.$vScroll;
			}.bind(this));
		} else {
			this.$vScroll = null;
		}
		
		if ((this.$pane.hScrollBar) || (this.$hScroll && this.$hScroll.getTag() == 'scrollbar')) {
			if (this.$pane.hScrollBar)
				this.$hScroll = $(this.$pane.hScrollBar);
			
			this.$hScroll.set({
				autoHide: this.options.scrollAutoHide,
				orientation: 'horizontal',
				visible: true,
				vOffset: this.$pane.vOffset + this.$pane.height,
				width: this.options.defaultScrollBarWidth,
				min: 0
			});
			
			this.$pane.__defineGetter__('hScroll', function () {
				return this.$hScroll;
			}.bind(this));
		} else {
			this.$hScroll = null;
		}
		
		if (this.$vScroll || this.$hScroll) {			
			this.$pane.addEvent('VisibleChanged', function (newval) {
				if (this.$vScroll 
					&& (this.$vScroll.max > 0 || !this.$vScroll.autoHide))
					this.$vScroll.visible = newval;
				if (this.$hScroll 
					&& (this.$hScroll.max > 0 || !this.$hScroll.autoHide))
					this.$hScroll.visible = newval;
			}.bind(this));
		}

		this.resize(this.$pane.width, this.$pane.height);
		el.resize = function(width, height) {
			this.resize(width, height);
		}.bind(this);
	},
	
	resize: function (width, height) {
		suppressUpdates();
		
		var paneWidth = width - (this.$vScroll ? this.$vScroll.width : 0);
		var paneHeight = height - (this.$hScroll ? this.$hScroll.width : 0);
		
		if (this.$vScroll) {
			this.$vScroll.height = paneHeight;
			
			if (!this.$pane.vScrollBar) {
				this.$vScroll.set({
					hOffset: paneWidth
				});
			}
		} 
		
		if (this.$hScroll) {
			this.$hScroll.height = paneWidth;
			
			if (!this.$pane.hScrollBar) {
				this.$hScroll.vOffset =  this.$pane.vOffset + paneHeight;
			}
		}
		
		this.$pane.set({
			width: paneWidth,
			height: paneHeight
		});
		
		resumeUpdates();
	}
});
KonPanel.implement(new Options);

Rectangle.create = function(x, y, width, height) {
	var rect = new Rectangle();
	rect.x = x;
	rect.y = y;
	rect.width = width;
	rect.height = height;
	return rect;
};

var KonWindow = new Class({
	options: {
		defaultStatusBarHeight: 20,
		previewResize: true
	},
	
	initialize: function (el, options) {
		if (el.getTag() != 'window') 
			throw "element should be a window";
		
		this.$window = el;		
		this.setOptions(options);
		
		this.$mainFrame = $E('frame[main]', this.$window);
		if (!this.$mainFrame)
			throw "main frame not found";
		
		var mainFrame = new KonPanel(this.$mainFrame);
		this.$status = $E('frame[status]', this.$window);
		this.$mainFrame.set({
			hOffset: 0,
			vOffset: 0
		});
	
		if (this.$status) {
			this.$status.set({
				hOffset: 0
			});
		}
		
		if (this.options.previewResize) {
			this.$previewResizer = new Element('canvas', {
				hOffset: 0,
				vOffset: 0,
				width: this.$window.width,
				height: this.$window.height
			});
			var ctx = this.$previewResizer.getContext('2d');
			ctx.strokeStyle = "rgba(20,20,20,0.8)";
			ctx.lineCap = "round";
			ctx.lineJoin = "round";
			ctx.lineWidth = 5.0;
			this.$window.adopt(this.$previewResizer);
			this.$previewResizer.orderAbove(null);
			
			this.$window.previewResize = this.previewResize;
		}
		
		this.resize(this.$window.width, this.$window.height);
		this.$window.resize = this.resize.bind(this);
		this.$window.visible = true;
		this.$window.__defineGetter__('mainFrame', this.__lookupGetter__('mainFrame').bind(this));
		this.$window.__defineGetter__('status', this.__lookupGetter__('status').bind(this));
	},
	
	previewResize: function (width, height) {
		if (!this.$previewResizer)
			return;
		
		this.$window.width = width;
		this.$window.height = height;
		if (!this.$window.style.oldBackgroundColor) {
			this.$window.style.oldBackgroundColor = this.$window.style.backgroundColor;
			this.$window.style.backgroundColor = "transparent";
			
			this.$window.getChildren().each(function (item) {
				if (!item.style.backgroundColor) {
					item.style.backgroundColor = this.$window.style.oldBackgroundColor;
					item.usedParentBGColor = true;
				}
			}, this);
		}
		
		this.$previewResizer.width = width;
		this.$previewResizer.height = height;
		
		var ctx = this.$previewResizer.getContext("2d");
		ctx.clearRect(0, 0, width, height);
		ctx.strokeRect(0, 0, width-ctx.lineWidth, height-ctx.lineWidth);
	},
	
	resize: function (width, height) {
		suppressUpdates();
		if (this.$previewResizer)
			this.$previewResizer.getContext("2d").clearRect(0, 0, width, height);
		
		this.$window.width = width;
		this.$window.height = height;
		if (this.$window.style.oldBackgroundColor) {
			this.$window.style.backgroundColor = this.$window.style.oldBackgroundColor;
			delete this.$window.style.oldBackgroundColor;
			
			this.$window.getChildren().each(function (item) {
				if (item.usedParentBGColor) {
					item.style.backgroundColor = null;
					delete item.usedParentBGColor;
				}
			}, this);
		}
		
		var statusBarHeight = this.$status ? this.$status.height : this.options.defaultStatusBarHeight;
		
		this.$mainFrame.resize(this.$window.width, 
			this.$window.height - (this.$status ? statusBarHeight : 0));
		
		if (this.$status) {
			this.$status.set({
				height: statusBarHeight, 
				width: this.$window.width,
				vOffset: this.$mainFrame.height
			});
			this.$status.flowLayout(Element.Layout.Right);
		}
		
		this.$window.recalcShadow();
		resumeUpdates();
	},
	
	get mainFrame () {
		return this.$mainFrame;
	},
	
	get status () {
		return this.$status;
	}
	
});
KonWindow.implement(new Options);

var KonTab = new Class({
	options: {
		itemsLayout: Element.Layout.Left,
		fill: true,
		scrollAutoHide: false,
		currentStyle: {
			fontStyle: "italic",
			fontWeight: "bold"
		}
	},
	
	initialize: function (el, current, options) {
		if (el.getTag() != "frame") {
			throw "tab must be a frame.";
		}
		
		this.$element = el;
		current = $pick(current, 0);
		this.$currentIndex = -1;
		this.setOptions(options);
		
		this.$tabs = $ES('frame[tabpage]', this.$element);
		this.$itemsRow = $E('frame[itemsRow]', this.$element);
		if (!this.$itemsRow) {
			throw "items row not found. Must specify the items row as a frame.";
		}
		this.$itemsRow.set({
			width: this.$element.width,
			vOffset: 0,
			hOffset: 0
		});
		this.$itemsRow.flowLayout(this.options.itemsLayout);
		
		this.$tabs.each(function (tab) {
			tab.visible = false;
			tab.hOffset = 0;
			tab.vOffset = this.$itemsRow.height;
			var pane = new KonPanel(tab, {'scrollAutoHide': this.options.scrollAutoHide});
			pane.resize(this.$element.width, this.$element.height - this.$itemsRow.height);
			
			if (this.options.fill) {
				this.$element.addEvent('WidthChanged', function (newval) {
					pane.resize(newval, this.$element.height - this.$itemsRow.height);
				}.bind(this));
				this.$element.addEvent('HeightChanged', function (newval) {
					pane.resize(this.$element.width, newval - this.$itemsRow.height);
				}.bind(this));
			}
		}.bind(this));
		
		this.$items = $ES('[item]', this.$itemsRow);
		if (this.$items.length != this.$tabs.length) {
			throw "items length must match tab page length. items: " + this.$items.length + "tabs: "+ this.$tabs.length;
		}
		this.$oldStyle = [];
		this.$items.each(function (item, index) {
			this.$oldStyle.push(KonStyle.cloneStyle(item));
			item.addEvent('Click', function (event) {
				this.currentIndex = index;
			}.bind(this));
		}.bind(this));
		
		this.currentIndex = current;
	},
	
	set currentIndex (current) {
		if (current >= this.$tabs.length) {
			throw "current page out of range. tab count: " + this.$tabs.length;
		}
		
		if (this.$currentIndex != current) {
			var oldIndex = this.$currentIndex;
		
			if (this.$currentIndex >= 0) {
				this.$items[this.$currentIndex].toggleStyle('current', 
					this.$oldStyle[this.$currentIndex], this.options.currentStyle);
				this.$tabs[this.$currentIndex].visible = false;
			}
			
			this.$currentIndex = current;
			this.$tabs[this.$currentIndex].visible = true;
			this.$items[current].toggleStyle('current', 
				this.$oldStyle[current], this.options.currentStyle);
				
			this.fireEvent('onCurrentTabChanged', current, 0);
		}
	},
	
	get currentIndex () {
		return this.$currentIndex;
	},
	
	get tabs () {
		return this.$tabs;
	},
	
	get currentTab() {
		return this.$tabs[this.currentIndex];
	}
});
KonTab.implement(new Options, new Events);

var PopupAlignment = {TopLeft: 0, TopRight: 1, BottomRight: 2, BottomLeft: 3};
var Popup = new Class({
	options: {
		alignment: PopupAlignment.BottomRight,
		fadeDuration: 500,
		duration: 1000
	},
	
	initialize: function (width, height, options) {
		this.setOptions(options);
		var workingRect = getMainDisplay().workRect;
		this.$window = $(new Window());
		this.$window.set({
			vOffset: workingRect.getMaxY() - height,
			hOffset: workingRect.getMaxX() - width,
			opacity: 0
		});
		this.$fadeOut = null;
	},
	
	show: function () {
		this.$window.level = 'topmost';
		if (this.$fadeOut != null) {
			this.$fadeOut.kill();
			this.$fadeOut = null;
		}

		animator.start(new FadeAnimation(this.$window, 
			255, this.options.fadeDuration, animator.kEaseInOut, 
			(function () {
				(function () {			
					this.$fadeOut = new FadeAnimation(this.$window, 
							0, this.options.fadeDuration, animator.kEaseOut , function() {
								this.$fadeOut = null;
							})
					animator.start(this.$fadeOut);
				}).delay(this.options.duration, this);
			}).bind(this)));
	}
});
Popup.implement(new Options);

var cache = function (fn) {
	var cache = new Hash();
	return function() {
		var args = $A(arguments).join(',');
		if (cache.hasKey(args)) {
			return cache.get(args);
		} else {
			var value = fn.apply(fn, arguments);
			cache.set(args, value);
			return value;
		}
	};
}

var getAlbumArtImg = cache(function (filename) {
	var songDir = filename.substring(0, filename.lastIndexOf("\\"));
	var cover;
	if (filesystem.itemExists(songDir + "\\cover.jpg")) {
		cover = songDir + "\\cover.jpg";
	}
	else if (filesystem.itemExists(songDir + "\\cover.png")) {
		cover = songDir + "\\cover.png";
	} else {
		var fileList = filesystem.getDirectoryContents(songDir, false);				
		var i = fileList.find(function(item, i) {
			var ext = fileList[i].split('.').getLast().toLowerCase();
			return ( ext == "png" || ext == "jpg" || ext == "jpeg");
		});
		if (i >= 0) {
			cover = songDir + "\\" + fileList[i];
		}
	}
	if (!cover) {
		cover = "Resources/noartwork.png";
	}
	return cover;
});

var timestamp = function () {
	return (Date.now() / 1000).toInt();
}

var FadeButton = new Class({
	options: {
		duration: 300,
		startOpacity: 80,
		endOpacity: 255
	},
	
	fadein: function () {
		animator.start(new FadeAnimation(this.element, this.options.endOpacity, this.options.duration, animator.kEaseIn));
	},
	
	fadeout: function () {
		animator.start(new FadeAnimation(this.element, this.options.startOpacity, this.options.duration, animator.kEaseOut));
	},
	
	initialize: function (element, options) {
		this.setOptions(options);
		this.element = $(element);
		this.element.style.opacity = this.options.startOpacity;
		this.element
			.addEvent('MouseEnter', this.fadein.bind(this))
			.addEvent('MouseExit', this.fadeout.bind(this));
	}
});
FadeButton.implement(new Options);